﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageSystem.Managed.Rpc;

namespace RpcGenerator.Lua
{
    class LuaProxyGenerator
    {
        public static string Generate(Type type, IMessageSerializer serializer, List<MessageDescription> allDescriptions)
        {
            MessageDescriptionGenerator mdgenerator = new MessageDescriptionGenerator();
            List<MessageDescription> requestDescriptions = allDescriptions.Where(description => description.IsRequest == true).ToList();

            string proxyName = type.Name+"Proxy";
            if (proxyName[0] == 'I')
                proxyName = proxyName.Remove(0, 1);
            serializer.NewLine("json = require('json');");
            serializer.NewLine();
            serializer.NewLine(proxyName + " = { };");
            GenerateCreateFunction(type, proxyName, serializer);

            requestDescriptions.ForEach(md => GenerateFunction(proxyName, serializer, md));

            GenerateMethodTable(proxyName, serializer, requestDescriptions);

            return proxyName + ".lua";
        }

        private static void GenerateCreateFunction(Type type,string proxyName, IMessageSerializer serializer)
        {
            serializer.NewLine();
            serializer.NewLine(string.Format("function {0}.New(domain,sessionid)", proxyName));
            serializer.BeginBlock(string.Empty);
            {
                serializer.NewLine(string.Format("local proxyid = ProxyCreate(domain,{0},sessionid);", RpcControl.GetServiceId(type)));
                serializer.NewLine("local proxy = { _id = proxyid };");
                serializer.NewLine("local metatable = { __index = " + string.Format("{0}.Methods", proxyName) + " };");
                serializer.NewLine("setmetatable(proxy,metatable);");
                serializer.NewLine("return proxy;");
            }
            serializer.EndBlock("end");
        }

        private static void GenerateFunction(string proxyName, IMessageSerializer serializer,MessageDescription md)
        {
            serializer.NewLine();
            serializer.NewLine();
            serializer.NewLine(string.Format("function {0}:{1}(", proxyName, md.Method.Method.Name));
            if (md.Fields.Count > 0)
            {
                MessageFieldDescription lastField = md.Fields[md.Fields.Count - 1];
                md.Fields.ForEach(fieldDescription =>
                {
                    if (lastField != fieldDescription)
                    {
                        serializer.Apppend(fieldDescription.Name + ",");
                    }
                    else
                    {
                        serializer.Apppend(fieldDescription.Name);
                    }
                });
            }

            if (md.Response == null)
            {
                serializer.BeginBlock(string.Empty);
                {
                    serializer.NewLine("local t = { ");
                    if (md.Fields.Count > 0)
                    {
                        MessageFieldDescription lastField = md.Fields[md.Fields.Count - 1];
                        md.Fields.ForEach(fieldDescription =>
                        {
                            if (lastField != fieldDescription)
                            {
                                serializer.Apppend(string.Format("{0} = {0},", fieldDescription.Name));
                            }
                            else
                            {
                                serializer.Apppend(string.Format("{0} = {0}", fieldDescription.Name));
                            }
                        });
                    }
                    serializer.Apppend(" };");
                    serializer.NewLine("local jsonstring = json.encode(t);");
                    serializer.NewLine(string.Format("local messageid = {0};", md.MessageId));
                    serializer.NewLine("ProxyCall1(self._id,messageid,jsonstring);");
                }
            }
            else
            {
                serializer.Apppend(",callback)");

                serializer.BeginBlock(string.Empty);
                {
                    serializer.NewLine("local t = { ");
                    if (md.Fields.Count > 0)
                    {
                        MessageFieldDescription lastField = md.Fields[md.Fields.Count - 1];
                        md.Fields.ForEach(fieldDescription =>
                        {
                            if (lastField != fieldDescription)
                            {
                                serializer.Apppend(string.Format("{0} = {0},", fieldDescription.Name));
                            }
                            else
                            {
                                serializer.Apppend(string.Format("{0} = {0}", fieldDescription.Name));
                            }
                        });
                    }
                    serializer.Apppend(" };");
                    serializer.NewLine("local jsonstring = json.encode(t);");
                    serializer.NewLine(string.Format("local messageid = {0};", md.MessageId));
                    serializer.NewLine("ProxyCall2(self._id,messageid,jsonstring,callback);");
                }
            }
            serializer.EndBlock("end");
        }

        private static void GenerateMethodTable(string proxyName,IMessageSerializer serializer, List<MessageDescription> allDescriptions)
        {
            serializer.NewLine();
            serializer.NewLine();
            serializer.NewLine(string.Format("{0}.Methods = ",proxyName));
            serializer.NewLine("    {");
            if (allDescriptions.Count > 0)
            {
                MessageDescription lastMD = allDescriptions[allDescriptions.Count - 1];
                allDescriptions.ForEach(md =>
                {
                    if (md != lastMD)
                    {
                        serializer.NewLine(string.Format("      {0} = {1}.{0},",md.Method.Method.Name,proxyName));
                    }
                    else
                    {
                        serializer.NewLine(string.Format("      {0} = {1}.{0}", md.Method.Method.Name, proxyName));
                    }
                });
            }
            serializer.NewLine("    };");
        }
    }
}
